home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / questpgr.c < prev    next >
C/C++ Source or Header  |  1993-01-25  |  12KB  |  506 lines

  1. /*    SCCS Id: @(#)questpgr.c    3.1    93/01/20    */
  2. /*    Copyright 1991, M. Stephenson          */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include "hack.h"
  6.  
  7. #ifdef MULDGN
  8. /*  quest-specific pager routines. */
  9.  
  10. #include "qtext.h"
  11.  
  12. #define QTEXT_FILE    "quest.dat"
  13. #if defined(MICRO) && !defined(AMIGA)
  14. # define RDMODE "rb"
  15. #else
  16. # define RDMODE "r"
  17. #endif
  18.  
  19. #ifndef SEEK_SET
  20. # define SEEK_SET 0
  21. #endif
  22.  
  23. /* #define DEBUG    /* uncomment for debugging */
  24.  
  25. static void FDECL(Fread, (genericptr_t,int,int,FILE    *));
  26. static struct qtmsg * FDECL(construct_qtlist, (long));
  27. static unsigned NDECL(class_index);
  28. static const char * NDECL(intermed);
  29. static const char * NDECL(neminame);
  30. static const char * NDECL(guardname);
  31. static const char * NDECL(homebase);
  32. static struct qtmsg * FDECL(msg_in, (struct qtmsg *,int));
  33. static void FDECL(convert_arg, (CHAR_P));
  34. static void NDECL(convert_line);
  35. static void FDECL(deliver_by_pline, (struct qtmsg *));
  36. static void FDECL(deliver_by_window, (struct qtmsg *));
  37.  
  38. static char    in_line[80], cvt_buf[64], out_line[128];
  39. static struct    qtlists    qt_list;
  40. static    FILE    *msg_file;
  41.  
  42. #ifdef DEBUG
  43. static void NDECL(dump_qtlist);
  44.  
  45. static void
  46. dump_qtlist()    /* dump the character msg list to check appearance */
  47. {
  48.     struct    qtmsg    *msg;
  49.     long    size;
  50.  
  51.     for (msg = qt_list.chclass; msg->msgnum > 0; msg++) {
  52.         pline("msgnum %d: delivery %c",
  53.             msg->msgnum, msg->delivery);
  54.         more();
  55.         (void) fseek(msg_file, msg->offset, SEEK_SET);
  56.         deliver_by_window(msg);
  57.     }
  58. }
  59. #endif /* DEBUG */
  60.  
  61. static void
  62. Fread(ptr, size, nitems, stream)
  63. genericptr_t    ptr;
  64. int    size, nitems;
  65. FILE    *stream;
  66. {
  67.     int cnt;
  68.  
  69.     if ((cnt = fread(ptr, size, nitems, stream)) != nitems) {
  70.  
  71.         panic("PREMATURE EOF ON QUEST TEXT FILE!\nExpected %d bytes - got %d\n",
  72.             (size * nitems), (size * cnt));
  73.     }
  74. }
  75.  
  76. static struct qtmsg *
  77. construct_qtlist(hdr_offset)
  78. long    hdr_offset;
  79. {
  80.     struct qtmsg *msg_list;
  81.     int    n_msgs;
  82.  
  83.     (void) fseek(msg_file, hdr_offset, SEEK_SET);
  84.     Fread(&n_msgs, sizeof(int), 1, msg_file);
  85.     msg_list = (struct qtmsg *) alloc((n_msgs+1)*sizeof(struct qtmsg));
  86.  
  87.     /*
  88.      * Load up the list.
  89.      */
  90.     Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file);
  91.  
  92.     msg_list[n_msgs].msgnum = -1;
  93.     return(msg_list);
  94. }
  95.  
  96. void
  97. load_qtlist()
  98. {
  99.  
  100.     int    n_classes, i;
  101.     char    qt_classes[N_HDR];
  102.     long    qt_offsets[N_HDR];
  103.  
  104.     msg_file = fopen_datafile(QTEXT_FILE, RDMODE);
  105.     if (!msg_file)
  106.         panic("\rCANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE);
  107.  
  108.     /*
  109.      * Read in the number of classes, then the ID's & offsets for
  110.      * each header.
  111.      */
  112.  
  113.     Fread(&n_classes, sizeof(int), 1, msg_file);
  114.     Fread(qt_classes, sizeof(char), n_classes, msg_file);
  115.     Fread(qt_offsets, sizeof(long), n_classes, msg_file);
  116.  
  117.     /*
  118.      * Now construct the message lists for quick reference later
  119.      * on when we are actually paging the messages out.
  120.      */
  121.  
  122.     qt_list.common = qt_list.chclass = (struct qtmsg *)0;
  123.  
  124.     for (i = 0; i < n_classes; i++) {
  125.         if (qt_classes[i] == COMMON_ID)
  126.         qt_list.common = construct_qtlist(qt_offsets[i]);
  127.         else if (qt_classes[i] == pl_character[0])
  128.         qt_list.chclass = construct_qtlist(qt_offsets[i]);
  129.     }
  130.  
  131.     if (!qt_list.common || !qt_list.chclass)
  132.         impossible("load_qtlist: cannot load quest text.");
  133. #ifdef DEBUG
  134.     dump_qtlist();
  135. #endif
  136.     return;    /* no ***DON'T*** close the msg_file */
  137. }
  138.  
  139. static struct qt_matrix {
  140.  
  141.     const char *intermed;    /* intermediate goal text */
  142.     const char *homebase;    /* leader's "location" */
  143.  
  144.     short    ldrnum,        /* mons[] indicies */
  145.         neminum,
  146.         guardnum;
  147.  
  148.     short    mtyp1, mtyp2;    /* monster types for enemies 0 == random */
  149.     char    msym1, msym2;    /* monster classes for enemies */
  150.  
  151.     short    artinum;    /* index of quest artifact */
  152.  
  153. } qt_matrix[] = {
  154.  
  155. /* A */ { "the tomb of the Toltec Kings",
  156.       "the College of Archeology",
  157.       PM_LORD_CARNARVON, PM_MINION_OF_HUHETOL, PM_STUDENT,
  158.       0, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY,
  159.       ART_ORB_OF_DETECTION },
  160.  
  161. /* B */ { "the Duali Oasis",
  162.       "the Camp of the Duali Tribe",
  163.       PM_PELIAS, PM_THOTH_AMON, PM_CHIEFTAIN,
  164.       PM_OGRE, PM_TROLL, S_OGRE, S_TROLL,
  165.       ART_HEART_OF_AHRIMAN },
  166.  
  167. /* C */ { "the Dragon's Lair",
  168.       "the Caves of the Ancestors",
  169.       PM_SHAMAN_KARNOV, PM_CHROMATIC_DRAGON, PM_NEANDERTHAL,
  170.       PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT,
  171.       ART_SCEPTRE_OF_MIGHT },
  172.  
  173. /* E */ { "the Goblins' Cave",
  174.       "the great Circle of Earendil",
  175.       PM_EARENDIL, PM_GOBLIN_KING, PM_HIGH_ELF,
  176.       PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE,
  177.       ART_PALANTIR_OF_WESTERNESSE },
  178.  
  179. /* E */ { "the Goblins' Cave",
  180.       "the great Circle of Elwing",
  181.       PM_ELWING, PM_GOBLIN_KING, PM_HIGH_ELF,
  182.       PM_URUK_HAI, PM_OGRE, S_ORC, S_OGRE,
  183.       ART_PALANTIR_OF_WESTERNESSE },
  184.  
  185. /* H */ { "the Temple of Coeus",
  186.       "the Isle of the Healers",
  187.       PM_HIPPOCRATES, PM_CYCLOPS, PM_NURSE,
  188.       PM_GIANT_RAT, PM_APE, S_RODENT, S_YETI,
  189.       ART_STAFF_OF_AESCULAPIUS },
  190.  
  191. /* K */ { "the Isle of Glass",
  192.       "Camelot Castle",
  193.       PM_KING_ARTHUR, PM_IXOTH, PM_PAGE,
  194.       PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY,
  195.       ART_MAGIC_MIRROR_OF_MERLIN },
  196.  
  197. /* P */ { "the Temple of Nalzok",
  198.       "the Great Temple",
  199.       PM_ARCH_PRIEST, PM_NALZOK, PM_ACOLYTE,
  200.       PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH,
  201.       ART_MITRE_OF_HOLINESS },
  202.  
  203. /* R */ { "the Asassins' Guild Hall",
  204.       "the Thieves' Guild Hall",
  205.       PM_MASTER_OF_THIEVES, PM_MASTER_ASSASSIN, PM_THUG,
  206.       PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA,
  207.       ART_MASTER_KEY_OF_THIEVERY },
  208.  
  209. /* S */ { "the Shogun's Castle",
  210.       "the castle of the Taro Clan",
  211.       PM_LORD_SATO, PM_ASHIKAGA_TAKAUJI, PM_NINJA,
  212.       PM_WOLF, PM_STALKER, S_DOG, S_STALKER,
  213.       ART_TSURUGI_OF_MURAMASA },
  214.  
  215. #ifdef TOURIST
  216. /* T */ { "the Thieves' Guild Hall",
  217.       "the Traveller's Aid Office",
  218.       PM_TWOFLOWER, PM_MASTER_OF_THIEVES, PM_GUIDE,
  219.       PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR,
  220.       ART_YENDORIAN_EXPRESS_CARD },
  221. #endif
  222.  
  223. /* V */ { "the cave of Surtur",
  224.       "the Shrine of Destiny",
  225.       PM_NORN, PM_LORD_SURTUR, PM_WARRIOR,
  226.       PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT,
  227.       ART_ORB_OF_FATE },
  228.  
  229. /* W */ { "the Tower of Darkness",
  230.       "the Tower of the Balance",
  231.       PM_WIZARD_OF_BALANCE, PM_DARK_ONE, PM_APPRENTICE,
  232.       PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH,
  233.       ART_EYE_OF_THE_AETHIOPICA },
  234.  
  235. /* - */ { "", "", 0, 0, 0, 0, 0, 0, 0, 0 }
  236. };
  237.  
  238. static unsigned
  239. class_index()
  240. {
  241.     switch (pl_character[0]) {
  242.  
  243.         case 'A':    return(0);
  244.         case 'B':    return(1);
  245.         case 'C':    return(2);
  246.         case 'E':    return(3+flags.female);
  247.         case 'H':    return(5);
  248.         case 'K':    return(6);
  249.         case 'P':    return(7);
  250.         case 'R':    return(8);
  251.         case 'S':    return(9);
  252. #ifdef TOURIST
  253.         case 'T':    return(10);
  254.         case 'V':    return(11);
  255.         case 'W':    return(12);
  256.         default:    return(13);
  257. #else
  258.         case 'V':    return(10);
  259.         case 'W':    return(11);
  260.         default:    return(12);
  261. #endif
  262.     }
  263. }
  264.  
  265. const char *
  266. ldrname()    /* return your class leader's name */
  267. {
  268.     int i = qt_matrix[class_index()].ldrnum;
  269. /*    return(mons[qt_matrix[class_index()].ldrnum].mname); */
  270.     return(mons[i].mname);
  271. }
  272.  
  273. static const char *
  274. intermed()    /* return your intermediate target string */
  275. {
  276.     return(qt_matrix[class_index()].intermed);
  277. }
  278.  
  279. boolean
  280. is_quest_artifact(otmp)
  281. struct obj *otmp;
  282. {
  283.     return(otmp->oartifact == qt_matrix[class_index()].artinum);
  284. }
  285.  
  286. static const char *
  287. neminame()    /* return your class nemesis' name */
  288. {
  289.     return(mons[qt_matrix[class_index()].neminum].mname);
  290. }
  291.  
  292. static const char *
  293. guardname()    /* return your class leader's guard monster name */
  294. {
  295.     return(mons[qt_matrix[class_index()].guardnum].mname);
  296. }
  297.  
  298. static const char *
  299. homebase()    /* return your class leader's location */
  300. {
  301.     return(qt_matrix[class_index()].homebase);
  302. }
  303.  
  304. boolean
  305. leaderless()    /* return true iff leader is dead */
  306. {
  307.     int i = qt_matrix[class_index()].ldrnum;
  308.     return (u.nr_killed[i] > 0);
  309. }
  310.  
  311. static struct qtmsg *
  312. msg_in(qtm_list, msgnum)
  313. struct qtmsg *qtm_list;
  314. int    msgnum;
  315. {
  316.     struct qtmsg *qt_msg;
  317.  
  318.     for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++)
  319.         if (qt_msg->msgnum == msgnum) return(qt_msg);
  320.  
  321.     return((struct qtmsg *)0);
  322. }
  323.  
  324. static void
  325. convert_arg(c)
  326. char c;
  327. {
  328.     register const char *str;
  329.  
  330.     switch (c) {
  331.  
  332.         case 'p':    str = plname;
  333.             break;
  334.         case 'c':    str = pl_character;
  335.             break;
  336.         case 'r':    str = rank_of(u.ulevel, pl_character[0], flags.female);
  337.             break;
  338.         case 'R':    str = rank_of(MIN_QUEST_LEVEL, pl_character[0],
  339.                               flags.female);
  340.             break;
  341.         case 's':    str = (flags.female) ? "sister" : "brother";
  342.             break;
  343.         case 'S':    str = (flags.female) ? "daughter" : "son";
  344.             break;
  345.         case 'l':    str = ldrname();
  346.             break;
  347.         case 'i':    str = intermed();
  348.             break;
  349.         case 'o':    str = artiname(qt_matrix[class_index()].artinum);
  350.             break;
  351.         case 'n':    str = neminame();
  352.             break;
  353.         case 'g':    str = guardname();
  354.             break;
  355.         case 'H':    str = homebase();
  356.             break;
  357.         case 'a':    str = align_str(u.ualignbase[0]);
  358.             break;
  359.         case 'A':    str = align_str(u.ualign.type);
  360.             break;
  361.         case 'd':    str = u_gname();
  362.             break;
  363.         case 'D':    str = align_gname(A_LAWFUL);
  364.             break;
  365.         case 'C':    str = "chaotic";
  366.             break;
  367.         case 'N':    str = "neutral";
  368.             break;
  369.         case 'L':    str = "lawful";
  370.             break;
  371.         case 'x':    str = Blind ? "sense" : "see";
  372.             break;
  373.         case '%':    str = "%";
  374.             break;
  375.          default:    str = "";
  376.             break;
  377.     }
  378.     Strcpy(cvt_buf, str);
  379. }
  380.  
  381. static void
  382. convert_line()
  383. {
  384.     char *c, *cc;
  385.  
  386.     cc = out_line;
  387.     for (c = xcrypt(in_line); *c; c++) {
  388.  
  389.         *cc = 0;
  390.         switch(*c) {
  391.  
  392.         case '\r':
  393.         case '\n':
  394.             *(++cc) = 0;
  395.             return;
  396.  
  397.         case '%':
  398.             if (*(c+1)) {
  399.                 convert_arg(*(++c));
  400.                 switch (*(c+1)) {
  401.  
  402.                 case 'P': cvt_buf[0] = highc(cvt_buf[0]);
  403.                 case 'p': Strcpy(cvt_buf, makeplural(cvt_buf));
  404.                         c++; break;
  405.  
  406.                 default: break;
  407.                 }
  408.                 Strcat(cc, cvt_buf);
  409.                 cc += strlen(cvt_buf);
  410.                 break;
  411.             }    /* else fall through */
  412.  
  413.         default:
  414.             *cc++ = *c;
  415.             break;
  416.         }
  417.     }
  418.     *cc = 0;
  419.     return;
  420. }
  421.  
  422. static void
  423. deliver_by_pline(qt_msg)
  424. struct qtmsg *qt_msg;
  425. {
  426.     long    size;
  427.  
  428.     for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
  429.         (void) fgets(in_line, 80, msg_file);
  430.         convert_line();
  431.         pline(out_line);
  432.     }
  433.  
  434. }
  435.  
  436. static void
  437. deliver_by_window(qt_msg)
  438. struct qtmsg *qt_msg;
  439. {
  440.     long    size;
  441.     winid datawin = create_nhwindow(NHW_TEXT);
  442.  
  443.     for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) {
  444.         (void) fgets(in_line, 80, msg_file);
  445.         convert_line();
  446.         putstr(datawin, 0, out_line);
  447.     }
  448.     display_nhwindow(datawin, TRUE);
  449.     destroy_nhwindow(datawin);
  450. }
  451.  
  452. void
  453. com_pager(msgnum)
  454. int    msgnum;
  455. {
  456.     struct qtmsg *qt_msg;
  457.  
  458.     if (!(qt_msg = msg_in(qt_list.common, msgnum))) {
  459.         impossible("com_pager: message %d not found.", msgnum);
  460.         return;
  461.     }
  462.  
  463.     (void) fseek(msg_file, qt_msg->offset, SEEK_SET);
  464.     if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg);
  465.     else             deliver_by_window(qt_msg);
  466.     return;
  467. }
  468.  
  469. void
  470. qt_pager(msgnum)
  471. int    msgnum;
  472. {
  473.     struct qtmsg *qt_msg;
  474.  
  475.     if (!(qt_msg = msg_in(qt_list.chclass, msgnum))) {
  476.         impossible("qt_pager: message %d not found.", msgnum);
  477.         return;
  478.     }
  479.  
  480.     (void) fseek(msg_file, qt_msg->offset, SEEK_SET);
  481.     if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11"))
  482.         deliver_by_pline(qt_msg);
  483.     else    deliver_by_window(qt_msg);
  484.     return;
  485. }
  486.  
  487. struct permonst *
  488. qt_montype()
  489. {
  490.     int class = class_index();
  491.  
  492.     if (rn2(5)) {
  493.         if (qt_matrix[class].mtyp1 && rn2(5) &&
  494.              !(mons[qt_matrix[class].mtyp1].geno & G_GENOD))
  495.                 return(&mons[qt_matrix[class].mtyp1]);
  496.         return(mkclass(qt_matrix[class].msym1,0));
  497.     }
  498.     if (qt_matrix[class].mtyp2 && rn2(5) &&
  499.          !(mons[qt_matrix[class].mtyp1].geno & G_GENOD))
  500.             return(&mons[qt_matrix[class].mtyp2]);
  501.     return(mkclass(qt_matrix[class].msym2,0));
  502. }
  503. #endif /* MULDGN */
  504.  
  505. /*questpgr.c*/
  506.